from fastapi import HTTPException
from sqlalchemy import event
from sqlalchemy.orm.attributes import get_history
from sqlmodel import Field, Relationship, SQLModel

from app.auth.models.permissions import GenericPermissions
from app.auth.models.utils import (
    create_permissions_for_model,
    delete_permissions_for_model,
)
from app.core.handlers.database import SessionBackend
from app.core.handlers.loggers import logger


class ApiBase(SQLModel):
    method: str = Field(default=None, nullable=False)
    path: str = Field(default=None, nullable=False)
    description: str | None


class ApiCreate(ApiBase):
    code: str = Field(default=None, unique=True, index=True, nullable=False)


class ApiPublic(ApiBase): ...


class Api(ApiBase, table=True):
    id: int = Field(primary_key=True)
    code: str = Field(default=None, unique=True, index=True, nullable=False)
    description: str | None = Field(default=None)
    generic_permission: list[GenericPermissions] = Relationship(
        sa_relationship_kwargs={
            "primaryjoin": "and_(GenericPermissions.object_id==Api.id, foreign(GenericPermissions.content_type_id)==1)",
            "viewonly": True,
            "uselist": True,
        }
    )


# 监听 Api 模型的插入事件
@event.listens_for(Api, "after_insert")
def create_generic_permission(_mapper, connection, target):
    """
    当 Api 对象插入后，自动创建对应的 GenericPermissions 记录
    """
    db = SessionBackend(bind=connection)
    try:
        # 定义需要创建的权限列表
        permissions = [
            {
                "code": f"api_{target.code}_!access",
                "description": f"禁止访问API {target.code}",
            }
        ]

        # 使用通用函数创建权限记录
        create_permissions_for_model(
            db, target, content_type_id=1, permissions=permissions
        )
    except Exception as e:
        db.rollback()
        logger.info(f"创建API {target.id}的通用权限时出错: {e}")
        raise HTTPException(status_code=500, detail="创建API通用权限时出错")
    finally:
        db.close()


# 监听 Api 模型的更新事件
@event.listens_for(Api, "before_update")
def update_generic_permission(_mapper, _connection, target):
    """
    当 Api 对象更新前，检查是否修改了code字段
    如果修改了code字段，则抛出400错误
    如果没有修改code字段，则正常更新
    """
    # 检查code字段是否发生变化
    code_history = get_history(target, "code")
    if code_history.has_changes():
        # 如果code字段发生了变化，则抛出400错误
        raise HTTPException(status_code=400, detail="Api表code字段创建后不允许修改")

    # 如果code字段没有变化，则允许正常更新
    # (不需要执行任何操作，更新会正常进行)


# 监听 Api 模型的删除事件
@event.listens_for(Api, "before_delete")
def delete_generic_permission(_mapper, connection, target):
    """
    当 Api 对象删除前，先删除相关的权限关联记录，再删除 GenericPermissions 记录
    """
    db = SessionBackend(bind=connection)
    try:
        delete_permissions_for_model(db, target, content_type_id=1)
    except Exception as e:
        db.rollback()
        logger.info(f"删除API id={target.id}的通用权限时出错: {e}")
        raise HTTPException(status_code=500, detail="删除API通用权限时出错")
    finally:
        db.close()
